package com.googlecode.curvedmetromaps.core.logic.costfunction;

import java.util.Arrays;

import com.googlecode.curvedmetromaps.core.model.MetroEdge;
import com.googlecode.curvedmetromaps.core.model.MetroMap;
import com.googlecode.curvedmetromaps.core.model.MetroStation;

public class AngularResolutionCost extends BaseCost {

	public AngularResolutionCost(MetroMap map) {
		super(map);
		createWeight("base", "Base weight", 1);
	}

	@Override
	public String getName() {
		return "Angular resolution";
	}

	@Override
	public double calculateCost() {
		double result = 0;
		int count = 0;

		for (MetroStation m : map.stations) {
			if (m.adj.length >= 3) {
				// Calculate angles
				int len = m.adj.length;
				double angles[] = new double[len];
				for (int i = 0; i < len; i++) {
					MetroEdge edge = map.getEdge(m, m.adj[i]);
					angles[i] = Math.atan2(edge.cpY - m.y, edge.cpX - m.x);
				}

				Arrays.sort(angles);
				double dAngles[] = new double[len];
				dAngles[0] = 2 * Math.PI + angles[0] - angles[len - 1];
				for (int i = 1; i < len; i++) {
					dAngles[i] = angles[i] - angles[i - 1];
				}
				
				double optAngle = 2 * Math.PI / m.degree;
				for (int i = 0; i < len; i++) {
					double cost = optAngle - dAngles[i];
					result += cost * cost;
				}

				count += m.degree;
			}
		}

		// Calculate average cost per vertex of degree 3 or more.
		result /= count;
		return getWeight("base") * result;
	}

}
